package com.mmall.pay.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.mmall.common.base.ServerResponse;
import com.mmall.common.enums.BooleanEnum;
import com.mmall.common.util.BeanUtil;
import com.mmall.pay.bean.MmallPayConfig;
import com.mmall.pay.enums.OptionTypeEnum;
import com.mmall.pay.enums.PayTypeEnum;
import com.mmall.pay.exception.MmallPayException;
import com.mmall.pay.param.CloseOrderParam;
import com.mmall.pay.param.CreateOrderParam;
import com.mmall.pay.param.QueryOrderParam;
import com.mmall.pay.param.RefundParam;
import com.mmall.pay.param.RefundQueryParam;
import com.mmall.pay.pojo.entity.PaymentFlowEntity;
import com.mmall.pay.result.CloseOrderResult;
import com.mmall.pay.result.CreateOrderResult;
import com.mmall.pay.result.QueryOrderResult;
import com.mmall.pay.result.RefundQueryResult;
import com.mmall.pay.result.RefundResult;
import com.mmall.pay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;


/**
 * @author gg
 * @version AlipayService.java, v 0.1 2019-05-27 17:24 gg
 */
@Slf4j
@Service("alipayService")
public class AlipayServiceImpl implements PayService {

    @Resource
    private PayConfigService payConfigService;

    @Resource
    private PaymentFlowService paymentFlowService;

    private static final String SERVER_URL = "https://openapi.alipay.com/gateway.do";

    private static final String DEV_SERVER_URL = "https://openapi.alipaydev.com/gateway.do";

    private static final String FORMAT = "json";

    private static final String CHARSET = "UTF-8";

    @Override
    public QueryOrderResult queryOrder(QueryOrderParam queryOrderParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(queryOrderParam);
        AlipayClient alipayClient = getAlipayClient(mmallPayConfig);
        AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
        alipayTradeQueryModel.setOutTradeNo(queryOrderParam.getOutTradeNo());
        alipayTradeQueryRequest.setBizModel(alipayTradeQueryModel);
        QueryOrderResult queryOrderResult = new QueryOrderResult();
        try {
            AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
            if (alipayTradeQueryResponse.isSuccess()) {
                queryOrderResult = BeanUtil.map(alipayTradeQueryResponse, QueryOrderResult.class);
            } else {
                queryOrderResult.setCode(alipayTradeQueryResponse.getCode());
                queryOrderResult.setSubMsg(alipayTradeQueryResponse.getSubMsg());
            }
        } catch (AlipayApiException e) {
            log.error("支付宝订单查询失败,orderNo:{},exception:{}", queryOrderParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return queryOrderResult;
    }

    @Override
    public CreateOrderResult createOrder(CreateOrderParam createOrderParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(createOrderParam);
        AlipayClient alipayClient = getAlipayClient(mmallPayConfig);
        CreateOrderResult createOrderResult;
        try {
            createOrderResult = execute(alipayClient, createOrderParam);
        } catch (AlipayApiException e) {
            log.error("支付宝支付失败:orderNo:{},exception{}", createOrderParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        if (createOrderResult != null && createOrderResult.isSuccess()) {
            //插入流水
            try {
                paymentFlowService.addFlow(
                        null,
                        createOrderParam.getOutTradeNo(),
                        createOrderParam.getMemberId(),
                        createOrderParam.getMemberName(),
                        createOrderParam.getPlatFormType(),
                        createOrderParam.getType(),
                        OptionTypeEnum.PAY,
                        createOrderParam.getPublicId(),
                        createOrderParam.getTotalFee());
            } catch (Exception e) {
                log.error("支付宝流水记录失败,orderNo:{},exception:{}", createOrderParam.getOutTradeNo(), e);
            }
        }
        return createOrderResult;
    }


    @Override
    public RefundResult refund(RefundParam refundParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(refundParam);
        AlipayClient alipayClient = getAlipayClient(mmallPayConfig);
        String refundFee = refundParam.getTotalFee().toString();
        refundFee = getTotalFee(refundFee);
        String notifyUrl = refundParam.getNotifyUrl();
        String returnUrl = refundParam.getReturnUrl();
        AlipayTradeRefundRequest alipayTradeRefundRequest = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
        alipayTradeRefundModel.setRefundAmount(refundFee);
        alipayTradeRefundModel.setOutTradeNo(refundParam.getOutTradeNo());
        alipayTradeRefundModel.setOutRequestNo(refundParam.getOutRefundNo());
        alipayTradeRefundRequest.setNotifyUrl(notifyUrl);
        alipayTradeRefundRequest.setReturnUrl(returnUrl);
        AlipayTradeRefundResponse alipayTradeRefundResponse;
        try {
            alipayTradeRefundResponse = alipayClient.execute(alipayTradeRefundRequest);
        } catch (AlipayApiException e) {
            log.error("支付宝退款失败:orderNo:{},exception:{}", refundParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        if (alipayTradeRefundResponse.isSuccess()) {
            //插入流水
            try {
                paymentFlowService.addFlow(
                        null,
                        refundParam.getOutTradeNo(),
                        refundParam.getMemberId(),
                        refundParam.getMemberName(),
                        refundParam.getPlatFormType(),
                        refundParam.getType(),
                        OptionTypeEnum.REFUND,
                        refundParam.getPublicId(),
                        refundParam.getTotalFee());
            } catch (Exception e) {
                log.error("支付宝流水记录失败,orderNo:{},exception:{}", refundParam.getOutTradeNo(), e);
            }
        }
        return BeanUtil.map(alipayTradeRefundResponse, RefundResult.class);
    }


    @Override
    public RefundQueryResult refundQuery(RefundQueryParam refundQueryParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(refundQueryParam);
        AlipayClient alipayClient = getAlipayClient(mmallPayConfig);
        AlipayTradeFastpayRefundQueryRequest alipayTradeFastpayRefundQueryRequest = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel alipayTradeFastpayRefundQueryModel = new AlipayTradeFastpayRefundQueryModel();
        alipayTradeFastpayRefundQueryModel.setOutRequestNo(refundQueryParam.getOutRequestNo());
        alipayTradeFastpayRefundQueryModel.setOutTradeNo(refundQueryParam.getOutTradeNo());
        alipayTradeFastpayRefundQueryRequest.setBizModel(alipayTradeFastpayRefundQueryModel);
        AlipayTradeFastpayRefundQueryResponse alipayTradeFastpayRefundQueryResponse;
        try {
            alipayTradeFastpayRefundQueryResponse = alipayClient.execute(alipayTradeFastpayRefundQueryRequest);
            return BeanUtil.map(alipayTradeFastpayRefundQueryResponse, RefundQueryResult.class);
        } catch (AlipayApiException e) {
            log.error("支付宝退款查询失败:orderNo:{},exception:{}", refundQueryParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
    }

    @Override
    public CloseOrderResult closeOrder(CloseOrderParam closeOrderParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(closeOrderParam);
        AlipayClient alipayClient = getAlipayClient(mmallPayConfig);
        AlipayTradeCloseRequest alipayTradeCloseRequest = new AlipayTradeCloseRequest();
        AlipayTradeCloseModel alipayTradeCloseModel = new AlipayTradeCloseModel();
        alipayTradeCloseModel.setOutTradeNo(closeOrderParam.getOutTradeNo());
        alipayTradeCloseRequest.setBizModel(alipayTradeCloseModel);
        alipayTradeCloseRequest.setNotifyUrl(closeOrderParam.getNotifyUrl());
        alipayTradeCloseRequest.setReturnUrl(closeOrderParam.getReturnUrl());
        AlipayTradeCloseResponse alipayTradeCloseResponse;
        CloseOrderResult closeOrderResult;
        try {
            alipayTradeCloseResponse = alipayClient.execute(alipayTradeCloseRequest);
            closeOrderResult  = BeanUtil.map(alipayTradeCloseResponse, CloseOrderResult.class);
            if (alipayTradeCloseResponse.isSuccess()) {
                //插入流水
                try {
                    PaymentFlowEntity paymentFlowEntity = new PaymentFlowEntity();
                    paymentFlowEntity.setOutTradeNo(closeOrderParam.getOutTradeNo());
                    paymentFlowEntity.setOptionType(OptionTypeEnum.PAY.getCode());
                    paymentFlowEntity.setIsDeleted(BooleanEnum.TRUE.getValue());
                    paymentFlowService.updateFlow(paymentFlowEntity);
                } catch (Exception e) {
                    log.error("支付宝流水记录失败,orderNo:{},exception:{}", closeOrderParam.getOutTradeNo(), e);
                }
            }
        } catch (AlipayApiException e) {
            log.error("支付宝关闭订单失败:orderNo:{},exception:{}", closeOrderParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return closeOrderResult;
    }

    private AlipayClient getAlipayClient(MmallPayConfig mmallPayConfig) {
        String url = mmallPayConfig.getDev() ? DEV_SERVER_URL : SERVER_URL;
        return new DefaultAlipayClient(
                url,
                mmallPayConfig.getAppId(),
                mmallPayConfig.getPrivateKey(),
                FORMAT,
                CHARSET,
                mmallPayConfig.getPublicKey(),
                mmallPayConfig.getSignType());
    }


    private CreateOrderResult execute(AlipayClient alipayClient, CreateOrderParam createOrderParam) throws AlipayApiException {
        CreateOrderResult createOrderResult = new CreateOrderResult();
        PayTypeEnum payTypeEnum = PayTypeEnum.getByValue(createOrderParam.getPayType());
        if (payTypeEnum == null) {
            throw new NullPointerException("没有该支付类型");
        }
        String totalFee = createOrderParam.getTotalFee().toString();
        totalFee = getTotalFee(totalFee);
        String subject = "MMALL 支付测试";
        String timeout = "30m";
        String body = createOrderParam.getBody();
        String outTradeNo = createOrderParam.getOutTradeNo();
        String notifyUrl = createOrderParam.getNotifyUrl();
        String returnUrl = createOrderParam.getReturnUrl();
        switch (payTypeEnum) {
            case ALIPAY_APP:
                AlipayTradeAppPayRequest alipayTradeAppPayRequest = new AlipayTradeAppPayRequest();
                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                model.setDisablePayChannels("credit_group");
                model.setBody(body);
                model.setSubject(subject);
                model.setOutTradeNo(outTradeNo);
                model.setTimeoutExpress(timeout);
                model.setTotalAmount(totalFee);
                alipayTradeAppPayRequest.setBizModel(model);
                alipayTradeAppPayRequest.setReturnUrl(returnUrl);
                alipayTradeAppPayRequest.setNotifyUrl(notifyUrl);
                AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(alipayTradeAppPayRequest);
                createOrderResult = BeanUtil.map(alipayTradeAppPayResponse, CreateOrderResult.class);
                break;
            case ALIPAY_WAP:
                AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
                AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
                //禁用信用卡渠道
                alipayTradeWapPayModel.setDisablePayChannels("credit_group");
                alipayTradeWapPayModel.setTotalAmount(totalFee);
                alipayTradeWapPayModel.setSubject(subject);
                alipayTradeWapPayModel.setOutTradeNo(outTradeNo);
                alipayTradeWapPayModel.setBody(body);
                alipayTradeWapPayModel.setTimeExpire(timeout);
                alipayTradeWapPayRequest.setBizModel(alipayTradeWapPayModel);
                alipayTradeWapPayRequest.setReturnUrl(returnUrl);
                alipayTradeWapPayRequest.setNotifyUrl(notifyUrl);
                AlipayTradeWapPayResponse alipayTradeWapPayResponse = alipayClient.pageExecute(alipayTradeWapPayRequest);
                createOrderResult = BeanUtil.map(alipayTradeWapPayResponse, CreateOrderResult.class);
                break;
            case ALIPAY_PC:
                AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
                AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
                //禁用信用卡渠道
                alipayTradePagePayModel.setTotalAmount(totalFee);
                alipayTradePagePayModel.setSubject(subject);
                alipayTradePagePayModel.setOutTradeNo(outTradeNo);
                alipayTradePagePayModel.setBody(body);
                alipayTradePagePayModel.setTimeExpire(timeout);
                alipayTradePagePayRequest.setBizModel(alipayTradePagePayModel);
                alipayTradePagePayRequest.setReturnUrl(returnUrl);
                alipayTradePagePayRequest.setNotifyUrl(notifyUrl);
                AlipayTradePagePayResponse alipayTradePagePayResponse = alipayClient.pageExecute(alipayTradePagePayRequest);
                createOrderResult = BeanUtil.map(alipayTradePagePayResponse, CreateOrderResult.class);
                break;
            case ALIPAY_QR:
                AlipayTradePrecreateRequest alipayTradePrecreateRequest = new AlipayTradePrecreateRequest();
                AlipayTradePrecreateModel alipayTradePrecreateModel = new AlipayTradePrecreateModel();
                alipayTradePrecreateModel.setTotalAmount(totalFee);
                alipayTradePrecreateModel.setSubject(subject);
                alipayTradePrecreateModel.setOutTradeNo(outTradeNo);
                alipayTradePrecreateModel.setBody(body);
                alipayTradePrecreateModel.setTimeoutExpress(timeout);
                alipayTradePrecreateRequest.setBizModel(alipayTradePrecreateModel);
                alipayTradePrecreateRequest.setReturnUrl(returnUrl);
                alipayTradePrecreateRequest.setNotifyUrl(notifyUrl);
                AlipayTradePrecreateResponse alipayTradePrecreateResponse = alipayClient.execute(alipayTradePrecreateRequest);
                createOrderResult = BeanUtil.map(alipayTradePrecreateResponse, CreateOrderResult.class);
                break;
            default:
        }
        return createOrderResult;
    }


    private String getTotalFee(String totalFee) {
        BigDecimal bigDecimal = new BigDecimal(totalFee);
        BigDecimal onHundred = new BigDecimal("100");
        totalFee = bigDecimal.divide(onHundred, 2, BigDecimal.ROUND_UP).toString();
        return totalFee;
    }


}
